/*
 * Quadruple.cpp
 *
 *  Created on: Nov 25, 2011
 *      Author: bkoziak
 */

#include "Quadruple.h"
#include "parser.h"
#include "global.h"

Quadruple::Quadruple() {
	this->typOperatora = NONE;
	this->arg1 = NULL;
	this->arg2 = NULL;
	this->rezultatSkoku = "";
	this->rezultat = NULL;
}
Quadruple::Quadruple(int typOperatora, Symbol* arg1, Symbol* arg2,
		string rezultatSkoku) {
	this->typOperatora = typOperatora;
	this->arg1 = arg1;
	this->arg2 = arg2;
	this->rezultat = NULL;
	this->rezultatSkoku = rezultatSkoku;
}

Quadruple::Quadruple(int typOperatora, Symbol* arg1, Symbol* arg2,
		Symbol* rezultat) {
	this->typOperatora = typOperatora;
	this->arg1 = arg1;
	this->arg2 = arg2;
	this->rezultat = rezultat;
	this->rezultatSkoku = "";
}
Quadruple::Quadruple(int typOperatora, Symbol* arg1, Symbol* arg2) {
	this->typOperatora = typOperatora;
	this->arg1 = arg1;
	this->arg2 = arg2;
	this->rezultat = NULL;
	this->rezultatSkoku = "";
}
string Quadruple::getAdres(Symbol* s) {
	stringstream ss;
	if (s->getTypSymbolu() == Symbol::STALA) {
		if (this->getTypZmiennej() == Symbol::INTEGER
				|| s->getTypZmiennej() == Symbol::INTEGER) {
			ss << "#" << s->getLexem();
		} else {
			ss << "#" << s->getLexem();
		}
		//TODO:Konwersje
		return ss.str();
	}
	if (s->getAdresowanie() == Symbol::POSREDNIE) {
		ss << "*";
	}
	if (s->getZakres() != 0) {
		ss << "BP";
		ss << (s->getAdres() > 0 ? "+" : "");
	}
	ss << s->getAdres();
	return ss.str();
}

string Quadruple::getBezposredniAdres(Symbol* symbol) {
	stringstream ss;
	if (symbol->getAdresowanie() == Symbol::BEZPOSREDNIE) {
		ss << "#";
	}
	if (symbol->getZakres() != 0) {
		ss << "BP";
		ss << (symbol->getAdres() > 0 ? "+" : "");
	}
	ss << symbol->getAdres();
	return ss.str();
}

Symbol::TYP_ZMIENNEJ Quadruple::getTypZmiennej() {
	if (arg2 == NULL) {
		return arg1->getTypZmiennej();
	}
	//wartosc przechowywana jako double, dlatego jesli obie sa stalymi, to bez konwersji mozna podciagnac pod real cale wyrazenie
	if (arg1->getTypSymbolu() == Symbol::STALA
			&& arg2->getTypSymbolu() == Symbol::STALA) {
		if (arg1->getTypZmiennej() == Symbol::REAL
				|| arg2->getTypZmiennej() == Symbol::REAL) {
			return Symbol::REAL;
		} else {
			return Symbol::INTEGER;
		}
	}
	//jeden z symboli jest stala - typ wyrazenia typem zmiennej
	if (arg1->getTypSymbolu() == Symbol::STALA) {
		return arg2->getTypZmiennej();
	}
	if (arg2->getTypSymbolu() == Symbol::STALA) {
		return arg1->getTypZmiennej();
	}

	//rozne typy
	if (arg1->getTypZmiennej() != arg2->getTypZmiennej()) {
		//TODO: Blad
	}

	//zgodne typy
	return arg1->getTypZmiennej();
}
string Quadruple::getAsm() {
	stringstream ss;
	string typ;
	switch (typOperatora) {
	case JUMP:
		ss << "\tjump.i\t#" << rezultatSkoku;
		break;
	case LABEL:
		ss << label << ":";
		break;
	case ASSIGNOP:
	case MOV:
		typ = arg1->getTypZmiennej() == Symbol::INTEGER ? ".i\t" : ".r\t";
		ss << "\tmov" << typ << getAdres(arg1) << ",\t" << getAdres(arg2);
		break;
	case PLUS:
		typ = rezultat->getTypZmiennej() == Symbol::INTEGER ? ".i\t" : ".r\t";
		ss << "\tadd" << typ << getAdres(arg1) << ",\t" << getAdres(arg2)
				<< ",\t" << getAdres(rezultat);
		break;
	case MINUS:
		typ = rezultat->getTypZmiennej() == Symbol::INTEGER ? ".i\t" : ".r\t";
		ss << "\tsub" << typ << getAdres(arg1) << ",\t" << getAdres(arg2)
				<< ",\t" << getAdres(rezultat);
		break;
	case MUL:
		typ = rezultat->getTypZmiennej() == Symbol::INTEGER ? ".i\t" : ".r\t";
		ss << "\tmul" << typ << getAdres(arg1) << ",\t" << getAdres(arg2)
				<< ",\t" << getAdres(rezultat);
		break;
	case DIV:
		typ = rezultat->getTypZmiennej() == Symbol::INTEGER ? ".i\t" : ".r\t";
		ss << "\tdiv" << typ << getAdres(arg1) << ",\t" << getAdres(arg2)
				<< ",\t" << getAdres(rezultat);
		break;
	case REALTOINT:
		ss << "\trealtoint.r\t" << getAdres(arg1) << ",\t"
				<< getAdres(rezultat);
		break;
	case INTTOREAL:
		ss << "\tinttoreal.i\t" << getAdres(arg1) << ",\t"
				<< getAdres(rezultat);
		break;
	case JEQ:
		typ = getTypZmiennej() == Symbol::INTEGER ? ".i\t" : ".r\t";
		ss << "\tje" << typ << getAdres(arg1) << ",\t" << getAdres(arg2)
				<< ",\t#" << rezultatSkoku;
		break;
	case WRITE:
		typ = getTypZmiennej() == Symbol::INTEGER ? ".i\t" : ".r\t";
		ss << "\twrite" << typ << getAdres(arg1);
		break;

	case READ:
		typ = getTypZmiennej() == Symbol::INTEGER ? ".i\t" : ".r\t";
		ss << "\tread" << typ << getAdres(arg1);
		break;

	case LEAVE:
		ss << "\tleave" << endl;
		ss << "\treturn";
		break;
	case INCSP:
		ss << "\tincsp.i\t#" << arg1->getRozmiarNaglowkaFunkcji();
		break;
	case ENTER:
		ss << arg1->getLexem() << ":" << endl;
		ss << "\tenter.i \t#" << arg1->getRozmiarPamieciFunkcji();
		break;
	case PUSH:
		ss << "\tpush.i\t" << getBezposredniAdres(arg1);
		break;
	case CALL:
		ss << "\tcall.i\t#" << arg1->getLexem();
		break;
	default:
		break;
	}
	ss << endl;
	return ss.str();
}

Symbol *Quadruple::getArg1() const {
	return arg1;
}

Symbol *Quadruple::getArg2() const {
	return arg2;
}

string Quadruple::getLabel() const {
	return label;
}

Symbol *Quadruple::getRezultat() const {
	return rezultat;
}

string Quadruple::getRezultatSkoku() const {
	return rezultatSkoku;
}

int Quadruple::getTypOperatora() const {
	return typOperatora;
}

void Quadruple::setArg1(Symbol *arg1) {
	this->arg1 = arg1;
}

void Quadruple::setArg2(Symbol *arg2) {
	this->arg2 = arg2;
}

void Quadruple::setLabel(string label) {
	this->label = label;
}

void Quadruple::setRezultat(Symbol *rezultat) {
	this->rezultat = rezultat;
}

void Quadruple::setRezultatSkoku(string rezultatSkoku) {
	this->rezultatSkoku = rezultatSkoku;
}

void Quadruple::setTypOperatora(int typOperatora) {
	this->typOperatora = typOperatora;
}

